/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/********************************************************************************************************
 * \file     Mcal.h                                                                                     *
 * \brief    AUTOSAR 4.3.1 MCALLib Driver                                                               *
 *                                                                                                      *
 * <table>                                                                                              *
 * <tr><th>Date           <th>Version                                                                   *
 * <tr><td>2025/01/06     <td>1.0.0                                                                     *
 * </table>                                                                                             *
 *******************************************************************************************************/
#ifndef MCAL_H
#define MCAL_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "OsIf.h"
#include "Compiler.h"
#include "Std_Types.h"
#include "RegHelper.h"

/* Version and Check Begin */
/* Version Info Begin */
#define MCAL_H_VENDOR_ID 0x8C
#define MCAL_H_AR_RELEASE_MAJOR_VERSION 4
#define MCAL_H_AR_RELEASE_MINOR_VERSION 3
#define MCAL_H_AR_RELEASE_REVISION_VERSION 1
#define MCAL_H_SW_MAJOR_VERSION 1
#define MCAL_H_SW_MINOR_VERSION 0
#define MCAL_H_SW_PATCH_VERSION 0
/* Version Info End */

/* Version Check Begin */
#if !defined(DISABLE_MCAL_ASR_VER_CHECK)
#if ((MCAL_H_AR_RELEASE_MAJOR_VERSION != COMPILER_H_AR_RELEASE_MAJOR_VERSION) || (MCAL_H_AR_RELEASE_MINOR_VERSION != COMPILER_H_AR_RELEASE_MINOR_VERSION) || (MCAL_H_AR_RELEASE_REVISION_VERSION != COMPILER_H_AR_RELEASE_REVISION_VERSION))
#error "Opps, Mcal.h and Compiler.h AutoSAR version not match!"
#endif
#endif /* !DISABLE_MCAL_ASR_VER_CHECK */
#if !defined(DISABLE_MCAL_SW_VER_CHECK)
#if ((MCAL_H_SW_MAJOR_VERSION != COMPILER_H_SW_MAJOR_VERSION) || (MCAL_H_SW_MINOR_VERSION != COMPILER_H_SW_MINOR_VERSION) || (MCAL_H_SW_PATCH_VERSION != COMPILER_H_SW_PATCH_VERSION))
#error "Opps, Mcal.h and Compiler.h Software version not match!"
#endif
#endif /* !DISABLE_MCAL_SW_VER_CHECK */
#if !defined(DISABLE_MCAL_ASR_VER_CHECK)
#if ((MCAL_H_AR_RELEASE_MAJOR_VERSION != STD_TYPES_H_AR_RELEASE_MAJOR_VERSION) || (MCAL_H_AR_RELEASE_MINOR_VERSION != STD_TYPES_H_AR_RELEASE_MINOR_VERSION) || (MCAL_H_AR_RELEASE_REVISION_VERSION != STD_TYPES_H_AR_RELEASE_REVISION_VERSION))
#error "Opps, Mcal.h and Std_Types.h AutoSAR version not match!"
#endif
#endif /* !DISABLE_MCAL_ASR_VER_CHECK */
#if !defined(DISABLE_MCAL_SW_VER_CHECK)
#if ((MCAL_H_SW_MAJOR_VERSION != STD_TYPES_H_SW_MAJOR_VERSION) || (MCAL_H_SW_MINOR_VERSION != STD_TYPES_H_SW_MINOR_VERSION) || (MCAL_H_SW_PATCH_VERSION != STD_TYPES_H_SW_PATCH_VERSION))
#error "Opps, Mcal.h and Std_Types.h Software version not match!"
#endif
#endif /* !DISABLE_MCAL_SW_VER_CHECK */
/* Version Check End */
/* Version and Check End */

#if defined(_ARMGCC_C_) || defined(_ARMCLANG_C_)

#define ASM_KEYWORD __asm

#define VAR_ALIGN(v, size) __attribute__((aligned(size))) v

#define ALIGNED(x) __attribute__((aligned(x)))

#endif /* defined(_ARMGCC_C_) || defined(_ARMCLANG_C_) */

#if defined(_IAR_C_)
#include <stdalign.h>

#define ASM_KEYWORD asm

// c11 align macro depend with  "stdalign.h"
#define VAR_ALIGN(v, size) alignas(size) v

#define ALIGNED(x) __attribute__((aligned(x)))

#endif /* defined(_IAR_C_) */

#if defined(_GCC_C_)

#define ASM_KEYWORD(x) __asm__ x

#define VAR_ALIGN(v, size) __attribute__((aligned(size))) v

#define ALIGNED(x) __attribute__((aligned(x)))

#endif /* defined(_GCC_C_) */

#if defined(_GHS_C_)

#define ASM_KEYWORD __asm__

#define VAR_ALIGN(v, size) __attribute__((aligned(size))) v

#define ALIGNED(x) __attribute__((aligned(x)))

#endif /* defined(_GHS_C_) */

#define MAX_MODULE 16 //max module id
#define MAX_AREA 16   //max critial area
extern uint32 start_ticks;
extern uint32 end_ticks;
extern uint32 max_ticks;
extern uint32 cur_ticks;
extern uint32 critial_area[MAX_MODULE][MAX_AREA];

#if defined(CFG_NOT_USED_AUTOSAR_OS)
#define ISR(IsrName) void IsrName(void)

#if !defined(CRITIAL_AREA_STATISTIC)
#define SuspendAllInterrupts() ASM_KEYWORD("cpsid if")
#else
#define SuspendAllInterrupts(a, b) \
    ASM_KEYWORD("cpsid if");       \
    start_ticks = read_pmccntr();

#endif

#if !defined(CRITIAL_AREA_STATISTIC)
#define ResumeAllInterrupts() ASM_KEYWORD("cpsie if")
#else
#define ResumeAllInterrupts(a, b)                             \
    do                                                        \
    {                                                         \
        end_ticks = read_pmccntr();                           \
        max_ticks = critial_area[a][b];                       \
        if (end_ticks > start_ticks)                          \
        {                                                     \
            cur_ticks = end_ticks - start_ticks;              \
        }                                                     \
        else                                                  \
        {                                                     \
            cur_ticks = (0xFFFFFFFF - end_ticks) + start_ticks;\
        }                                                     \
        if (max_ticks < cur_ticks)                            \
        {                                                     \
            critial_area[a][b] = cur_ticks;                   \
        }                                                     \
        ASM_KEYWORD("cpsie if");                              \
    } while (0)

#endif

#else
#if defined(CFG_BUILD_CHECK)
#define ISR(IsrName) void IsrName(void)
#endif /** #if !defined(CFG_BUILD_CHECK) */

#endif /** #if defined(CFG_NOT_USED_AUTOSAR_OS) */

#if defined(CFG_IRG_LOG) && !defined(CFG_ARM_VIC)

#if defined(CFG_EN_FUSALIB)
/* include fusa header file */
#include "FuSaLib_MonitorConfig.h"
#include "Fusa_Component.h"
#include "FSD_SemReg.h"
/* fusa sem error function */
extern FuSa_RltCodeEnum FuSaLib_MonitorTrigInt(Sem_IntOutputEnum value, uint32 errType, boolean en);
#define irq_log_report_sem_error(a, b, c) FuSaLib_MonitorTrigInt(a, b, c)
#else/* defined(CFG_EN_FUSALIB) */
#define irq_log_report_sem_error(a, b, c)
#endif/* defined(CFG_EN_FUSALIB) */

 #define IRQ_LOG_SPI_INT_BASE               (32U)
 #define IRQ_LOG_SPI_MAX_INTID              (402U + 32U)
 #define IRQ_LOG_IS_SPI(intid)              (((intid) >= IRQ_LOG_SPI_INT_BASE) && ((intid) <= IRQ_LOG_SPI_MAX_INTID))
 #define IRQ_LOG_NUM_INTR_PER_REG           (32U)
 #define IRQ_LOG_NUM_CFG_PER_REG            (16U)
 #define IRQ_LOG_BASE_ADDRESS               (0xF87A0000ul)

 #define irq_log_check_valid(x)                                                  \
     do                                                                          \
     {                                                                           \
         uint32 base;                                                            \
         uint32 idx;                                                             \
         uint32 mask;                                                            \
         if (IRQ_LOG_IS_SPI(x))                                                  \
         {                                                                       \
             idx = ((x) / IRQ_LOG_NUM_INTR_PER_REG) - 1U;                        \
             mask = 1UL << ((x) & (IRQ_LOG_NUM_INTR_PER_REG - 1U));              \
             base = IRQ_LOG_BASE_ADDRESS + (idx * 4U);                           \
             if (0U == (readl(base) & mask))                                     \
             {                                                                   \
                 irq_log_report_sem_error(SEM_OUTPUT_CPU, FUSALIB_MON_TRIG_INT_ERROR_TYPE_IRQLOG_CHECK, TRUE); \
             }                                                                   \
         }                                                                       \
     } while (0U);
#else
#define irq_log_check_valid(x) ((void)(x))
#endif /* defined(CFG_IRG_LOG) && !defined(CFG_ARM_VIC) */


/* pointer to pointer to variable */
#define P2P2VAR(ptrtype, memclass, ptrclass) ptrtype **

#ifdef __cplusplus
}
#endif

#endif /** #ifndef _MCAL_H_ */
